package org.nkumar.immortal.web;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.PageContext;
import java.io.InputStream;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.logging.Logger;

public final class ImmortalResourceURLProvider
{
    private static final Logger LOG = Logger.getLogger(ImmortalResourceURLProvider.class.getName());

    private static final String CHECK_FOR_DUPLICATE_SCRIPTS_PROP_NAME
            = "org.nkumar.immortal.web.checkForDuplicateScripts";
    private static final String SCRIPTS_LIST_ATTR_NAME
            = "org.nkumar.immortal.web.scriptList";

    static final String IMMORTAL_MAPPINGS_XML = "immortal_mappings.xml";

    private static final ImmortalResourceURLProviderConfig config;
    private static final boolean checkForDuplicateScripts;

    static
    {
        Map<String, Object> mappingConfig = null;
        InputStream in;
        try
        {
            in = ImmortalResourceURLProvider.class.getClassLoader()
                    .getResourceAsStream(IMMORTAL_MAPPINGS_XML);
        }
        catch (Exception ignore)
        {
            in = null;
        }
        config = new ImmortalResourceURLProviderConfig(in);

        checkForDuplicateScripts = "true".equalsIgnoreCase(
                System.getProperty(CHECK_FOR_DUPLICATE_SCRIPTS_PROP_NAME, "false"));
    }

    private ImmortalResourceURLProvider()
    {
    }

    /**
     * returns the mapped url for the passed old url.
     * The return url will start with servlet context name (if any),
     * which will be followed by the mapped versioned url of the resource.
     * If no mapping if found then the servlet context name is followed
     * by the old url itself.
     * Say for example "/css/main.css" was mapped to "/i_m_m_o_r_t_a_l/css/main_XYZ.css"
     * and the servlet context name is app then the returned url would be
     * "/app/i_m_m_o_r_t_a_l/css/main_XYZ.css".
     * @param pageContext
     * @param oldUrl
     * @return the mapped url as described above
     */
    public static String getVersionedUrl(final PageContext pageContext, final String oldUrl)
    {
        final HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
        return getVersionedUrlFromRequest(request, oldUrl);
    }

    /**
     * @see #getVersionedUrl(PageContext,String)
     */
    public static String getVersionedUrlFromRequest(final HttpServletRequest request, final String oldUrl)
    {
        checkForDuplicateScripts(request, oldUrl);
        return config.getVersionedUrlFromRequest(oldUrl, request.getContextPath());
    }

    private static void checkForDuplicateScripts(final HttpServletRequest request, final String url)
    {
        if (checkForDuplicateScripts && url.toLowerCase().endsWith(".js"))
        {
            Set<String> set = (Set<String>) request.getAttribute(SCRIPTS_LIST_ATTR_NAME);
            if (set == null)
            {
                set = new HashSet<String>();
                request.setAttribute(SCRIPTS_LIST_ATTR_NAME, set);
            }
            if (set.contains(url))
            {
                throw new RuntimeException("Script at '" + url + "' is used multiple times in the same request");
            }
            set.add(url);
        }
    }
}
